home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Programming / LEDA / source / src / arith / imul.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  11.5 KB  |  582 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  3.1c
  4. +
  5. +
  6. +  imul.c
  7. +
  8. +
  9. +  Copyright (c) 1994  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15. /*     imul.c        RD, 29.01.90    */
  16. /*    bug in IasIsrint fixed, RD, 32.08.91    */
  17. /*    sign bug in IasImuP fixed, RD, 26.2.92    */
  18. /*    Karatsuba-Verfahren, RD, 20.7.92    */
  19. /*    bug in memory usage in do_karatsuba, RD, 14.14.92    */
  20.  
  21. #include <LEDA/impl/iint.h>
  22. #include <LEDA/impl/iloc.h>
  23.  
  24.  
  25. #ifdef DO_NOT_USE_KARATSUBA
  26.  
  27. void IasImuI (accu, a, b)
  28.     pInteger accu;
  29.     const Integer *a, *b;
  30. /* accu=a*b; */
  31. {       register int i, al, bl, neededlength;
  32.         register pPLACE paccu, pa, pb;
  33.     if (accu==a) {
  34.         ImuasI(accu, b);
  35.         return;
  36.     }
  37.     if (accu==b) {
  38.         ImuasI(accu, a);
  39.         return;
  40.     }
  41.     al=a->length;
  42.     bl=b->length;
  43.         if (!al || !bl) {
  44.         Iasint(accu, 0);
  45.         return;
  46.         }
  47.         neededlength=al+bl;
  48.     if (neededlength > accu->maxlength) {
  49.         delvec(accu->vec, accu->maxlength);
  50.         accu->maxlength=neededlength;
  51.         paccu=newvec(&accu->maxlength);
  52.         accu->vec=paccu;
  53.     } else
  54.         paccu=accu->vec;
  55.         pa=a->vec;
  56.     pb=b->vec;
  57.     if (al > bl) {
  58.             for ( i = 0; i < al; i++)
  59.                 paccu[i] = 0;
  60.             for ( i = 0; i < bl; i++) 
  61.                 paccu[i+al] = 
  62.             vecmuladd(paccu+i, pa, pb[i], al);
  63.         } else {           
  64.             for ( i = 0; i < bl; i++)
  65.                 paccu[i] = 0;
  66.             for ( i = 0; i < al; i++) 
  67.                 paccu[i+bl] = 
  68.             vecmuladd(paccu+i, pb, pa[i], bl);
  69.         }
  70.         if (paccu[neededlength-1])
  71.             accu->length = neededlength;
  72.         else
  73.             accu->length = neededlength-1;
  74.         accu->sign = a->sign ^ b->sign;
  75. }        /* IasImuI */
  76.  
  77. void ImuasI(a, b)
  78.     pInteger a;
  79.     const Integer *b;
  80. /* a*=b; */
  81. {       int maxl;
  82.         register pPLACE paccu, pa, pb;
  83.         register int i, al, bl;
  84.     al=a->length;
  85.     bl=b->length;
  86.         if (!al || !bl) {
  87.         Iasint(a, 0);
  88.         return;
  89.         }
  90.         maxl=al+bl;
  91.         paccu=newvec(&maxl);
  92.         pa=a->vec;
  93.     pb=b->vec;
  94.     if (al > bl) {
  95.             for ( i = 0; i < al; i++)
  96.                 paccu[i] = 0;
  97.             for ( i = 0; i < bl; i++) 
  98.                 paccu[i+al] = 
  99.             vecmuladd(paccu+i, pa, pb[i], al);
  100.         } else {           
  101.             for ( i = 0; i < bl; i++)
  102.                 paccu[i] = 0;
  103.             for ( i = 0; i < al; i++) 
  104.                 paccu[i+bl] = 
  105.             vecmuladd(paccu+i, pb, pa[i], bl);
  106.         }
  107.     al+=bl;
  108.         if (paccu[al-1])
  109.             a->length = al;
  110.         else
  111.             a->length = al-1;
  112.         a->sign ^= b->sign;
  113.     delvec(a->vec, a->maxlength);
  114.     a->vec=paccu;
  115.     a->maxlength=maxl;
  116. }        /* ImuasI */
  117.  
  118. #else
  119. /* use karatsuba */
  120.  
  121. /* Prerequisite: enough space in the vectors to increase the length
  122.     appropriately, given with the built-in memory management.
  123. */
  124.  
  125. #ifndef KARATSUBA_LIMIT1
  126. #define KARATSUBA_LIMIT1 15
  127. #endif
  128. #ifndef KARATSUBA_LIMIT2
  129. #define KARATSUBA_LIMIT2 KARATSUBA_LIMIT1
  130. #endif
  131.  
  132. static void do_karatsuba( /* paccu, pa, pb, al, bl */ );
  133.  
  134. void IasImuI (accu, a, b)
  135.     Integer *accu;
  136.     const Integer *a, *b;
  137. /* accu=a*b; */
  138. /* Karatsuba, verwendet do_karatsuba */
  139. {       register int i, al, bl, neededlength;
  140.         register pPLACE paccu, pa, pb;
  141.  
  142.     if (accu==a) {
  143.         ImuasI(accu, b);
  144.         return;
  145.     }
  146.     if (accu==b) {
  147.         ImuasI(accu, a);
  148.         return;
  149.     }
  150.     al=a->length;
  151.     bl=b->length;
  152.         if (!al || !bl) {
  153.         Iasint(accu, 0);
  154.         return;
  155.         }
  156.         neededlength=al+bl;
  157.     if (neededlength > accu->maxlength) {
  158.         delvec(accu->vec, accu->maxlength);
  159.         accu->maxlength=neededlength;
  160.         paccu=newvec(&accu->maxlength);
  161.         accu->vec=paccu;
  162.     } else
  163.         paccu=accu->vec;
  164.     if (al > bl) {
  165.         if (bl <= KARATSUBA_LIMIT1) {
  166.             /* Standardmultiplikation */
  167.             pa=a->vec;
  168.         pb=b->vec;
  169.         for ( i = 0; i < al; i++)
  170.             paccu[i] = 0;
  171.         for ( i = 0; i < bl; i++) 
  172.             paccu[i+al] = 
  173.                 vecmuladd(paccu+i, pa, pb[i], al);
  174.         } else
  175.         do_karatsuba(paccu, a->vec, b->vec, al, bl);
  176.         } else {
  177.         if (al <= KARATSUBA_LIMIT1) {       
  178.             /* Standardmultiplikation */
  179.             pa=a->vec;
  180.         pb=b->vec;
  181.         for ( i = 0; i < bl; i++)
  182.             paccu[i] = 0;
  183.         for ( i = 0; i < al; i++) 
  184.             paccu[i+bl] = 
  185.                 vecmuladd(paccu+i, pb, pa[i], bl);
  186.         } else
  187.         do_karatsuba(paccu, b->vec, a->vec, bl, al);
  188.         }
  189.         if (paccu[neededlength-1])
  190.             accu->length = neededlength;
  191.         else
  192.             accu->length = neededlength-1;
  193.         accu->sign = a->sign ^ b->sign;
  194. }    /* IasImuI, karatsuba    */
  195.  
  196. void ImuasI(a, b)
  197.     pInteger a;
  198.     const Integer *b;
  199. /* a*=b; */
  200. /* Karatsuba, verwendet do_karatsuba */
  201. {       int maxl;
  202.         register pPLACE paccu, pa, pb;
  203.         register int i, al, bl;
  204.     al=a->length;
  205.     bl=b->length;
  206.         if (!al || !bl) {
  207.         Iasint(a, 0);
  208.         return;
  209.         }
  210.         maxl=al+bl;
  211.         paccu=newvec(&maxl);
  212.     if (al > bl) {
  213.         if (bl <= KARATSUBA_LIMIT1) {
  214.             /* Standardmultiplikation */
  215.             pa=a->vec;
  216.         pb=b->vec;
  217.         for ( i = 0; i < al; i++)
  218.             paccu[i] = 0;
  219.         for ( i = 0; i < bl; i++) 
  220.             paccu[i+al] = 
  221.                 vecmuladd(paccu+i, pa, pb[i], al);
  222.         } else
  223.         do_karatsuba(paccu, a->vec, b->vec, al, bl);
  224.         } else {
  225.         if (al <= KARATSUBA_LIMIT1) {       
  226.             /* Standardmultiplikation */
  227.             pa=a->vec;
  228.         pb=b->vec;
  229.         for ( i = 0; i < bl; i++)
  230.             paccu[i] = 0;
  231.         for ( i = 0; i < al; i++) 
  232.             paccu[i+bl] = 
  233.                 vecmuladd(paccu+i, pb, pa[i], bl);
  234.         } else
  235.         do_karatsuba(paccu, b->vec, a->vec, bl, al);
  236.         }
  237.     al+=bl;
  238.         if (paccu[al-1])
  239.             a->length = al;
  240.         else
  241.             a->length = al-1;
  242.         a->sign ^= b->sign;
  243.     delvec(a->vec, a->maxlength);
  244.     a->vec=paccu;
  245.     a->maxlength=maxl;
  246. }        /* ImuasI, karatsuba */
  247.  
  248.  
  249. static void do_karatsuba(paccu, pa, pb, al, bl)
  250.     PLACE *paccu, *pa, *pb;
  251.     int    al, bl;
  252.     /* now pb is the shorter number */
  253. {        PLACE *tprod, *tmp, *res;
  254.     int i, tmpl, k, q, r, n, n0, resl;
  255.  
  256.     /* calculate k minimal with 
  257.         bl <= 2^k*n0 and n0<=KARATSUBA_LIMIT2, n=2^k*n0 */
  258.     n0=bl;
  259.     k=0;
  260.     while (n0>KARATSUBA_LIMIT2) {
  261.         n0=(n0+1)/2;
  262.         k++;
  263.     }
  264.     n=n0<<k;
  265.     /* fill a, b with zeroes, maybe al <= n */
  266.     for (i=bl; i<n; i++)
  267.         pb[i]=0;
  268.     for (i=al; i<n; i++)
  269.         pa[i]=0;
  270.     /* split a */
  271.     q=al/n;
  272.     r=al%n;
  273.     if (q==0) {    /* case al < n */
  274.         q=1;
  275.         r=0;
  276.     }
  277.     /* Now get temporaries for result of karatsuba_mult and tmp */
  278.     tmpl=2*n;
  279.     tmp=newvec(&tmpl);
  280.     tprod=newvec(&tmpl);
  281.     /* Get temporary for result. */
  282.     resl=al+n;
  283.     res=newvec(&resl);
  284.     /* calculate via karatsuba_mult a_i * b, 0<= i <q */
  285.     karatsuba_mult(res, pa, pb, tmp, n);
  286.     for (i=1; i<q; i++) {
  287.         karatsuba_mult(tprod, &pa[i*n], pb, tmp, n);
  288.         cvadd(&res[i*n], &res[i*n], tprod, n , 2*n);
  289.     }
  290.     /* calculate a_q * b */
  291.     for (i=q*n; i<al; i++)
  292.         res[i+bl] = vecmuladd(&res[i], pb, pa[i], bl);
  293.     for (i=0; i<al+bl; i++)
  294.         paccu[i]=res[i];
  295.     delvec(tmp, tmpl);
  296.     delvec(tprod, tmpl);
  297.     delvec(res, resl);
  298. }        /* do_karatsuba */
  299.  
  300. #endif
  301. /* DO_NOT_USE_KARATSUBA */
  302.  
  303. #ifdef __GNUC__
  304. void IasImuP(Integer *accu, const Integer *b, PLACE c)
  305. #else
  306. void IasImuP(accu, b, c)
  307.     register Integer *accu;
  308.     const Integer *b;
  309.     PLACE c;
  310. #endif
  311. {    register int nl;
  312.     register PLACE carry;
  313.  
  314.     if (accu==b) {
  315.         ImuasP(accu, c);
  316.         return;
  317.     }
  318.     if (!c) {
  319.         Iasint(accu, 0);
  320.         return;
  321.     }
  322.     nl=b->length+1;
  323.     if (nl > accu->maxlength) {
  324.         delvec(accu->vec, accu->maxlength);
  325.         accu->maxlength=nl;
  326.         accu->vec=newvec(&accu->maxlength);
  327.     }
  328.     carry=vecmul(accu->vec, b->vec, c, b->length);
  329.     accu->vec[nl-1]=carry;
  330.     if (carry)
  331.         accu->length = nl;
  332.     else
  333.         accu->length = nl-1;
  334.     accu->sign=b->sign;
  335. }        /* IasImuP */
  336.  
  337. #ifdef __GNUC__
  338. void ImuasP(Integer *accu, PLACE b)
  339. #else
  340. void ImuasP(accu, b)
  341.     register pInteger accu;
  342.     PLACE b;
  343. #endif
  344. {    register PLACE carry, *paccu;
  345.     register int nl;
  346.     BOOLEAN neednew;
  347.     int maxl;
  348.  
  349.     if (!b) {
  350.         Iasint(accu, 0);
  351.         return;
  352.     }
  353.     nl=accu->length+1;
  354.     if (nl>accu->maxlength) {
  355.         neednew=TRUE;
  356.         maxl=nl;
  357.         paccu=newvec(&maxl);
  358.     } else {
  359.         paccu=accu->vec;
  360.         neednew=FALSE;
  361.     }
  362.     carry=vecmul(paccu, accu->vec, b, accu->length);
  363.     paccu[nl-1]=carry;
  364.     if (carry)
  365.         accu->length=nl;
  366.     if (neednew) {
  367.         delvec(accu->vec, accu->maxlength);
  368.         accu->vec=paccu;
  369.         accu->maxlength=maxl;
  370. }    }    /* ImuasP */
  371.  
  372. /****************************************************/
  373.  
  374. void IasIsrint(a, b, count)
  375.     register pInteger a;
  376.     register const Integer *b;
  377.     unsigned int count;
  378. /* Shift nach rechts */
  379. {    register PLACE accu, help, *pa, *pb;
  380.     register int i;
  381.     int pts, bts, bleft, nl;
  382.     if (a==b) {
  383.         Israsint(a, count);
  384.         return;
  385.     }
  386.     pts=count/LOGPLACE;
  387.     if (pts>=b->length) {
  388.         Ias0(a);
  389.         return;
  390.     }
  391.     bts=count%LOGPLACE;
  392.     bleft=LOGPLACE-bts;
  393.     nl=b->length-pts;
  394.     if (nl>a->maxlength) {
  395.         delvec(a->vec, a->maxlength);
  396.         a->maxlength=nl;
  397.         a->vec=newvec(&a->maxlength);
  398.     }
  399.     pa=a->vec;
  400.     pb=b->vec;
  401.     if ( !bts ) {
  402.         for (i=pts; i<b->length; i++)
  403.             pa[i-pts]=pb[i];
  404.         a->length=nl;
  405.         a->sign=b->sign;
  406.         return;
  407.     }
  408.     accu=pb[pts];
  409.     accu>>=bts;
  410.     for (i=pts+1; i<b->length; i++) {
  411.         help=pb[i];
  412.         accu|=(help<<bleft);
  413.         pa[i-pts-1]=accu;
  414.         accu=help>>bts;
  415.     }
  416.     pa[nl-1]=accu;
  417.     if (accu)
  418.         a->length=nl;
  419.     else
  420.         a->length=nl-1;
  421.     if (a->length)
  422.         a->sign=b->sign;
  423.     else
  424.         a->sign=PLUS;
  425. }        /* IasIsrint */
  426.  
  427. void Israsint(a, count)
  428.     register pInteger a;
  429.     unsigned int count;
  430. /* Shift nach rechts */
  431. {    register PLACE accu, help, *p;
  432.     register int i;
  433.     int pts, bts, bleft, l;
  434.     pts=count/LOGPLACE;
  435.     if (pts>=a->length) {
  436.         Ias0(a);
  437.         return;
  438.     }
  439.     bts=count%LOGPLACE;
  440.     bleft=LOGPLACE-bts;
  441.     p=a->vec;
  442.     if ( !bts ) {
  443.         for (i=pts; i<a->length; i++)
  444.             p[i-pts]=p[i];
  445.         a->length=a->length-pts;
  446.         return;
  447.     }
  448.     accu=p[pts];
  449.     accu>>=bts;
  450.     for (i=pts+1; i<a->length; i++) {
  451.         help=p[i];
  452.         accu|=(help<<bleft);
  453.         p[i-pts-1]=accu;
  454.         accu=help>>bts;
  455.     }
  456.     l=a->length-pts;
  457.     if (accu) {
  458.         p[l-1]=accu;
  459.         a->length=l;
  460.     } else
  461.         a->length=l-1;
  462.     if (!a->length)
  463.         a->sign=PLUS;
  464. }        /* Israsint */
  465.  
  466. void IasIslint(a, b, count)
  467.     register pInteger a;
  468.     register const Integer *b;
  469.     unsigned int count;
  470. /* Shift nach links */
  471. {    register PLACE accu, help, *pa, *pb;
  472.     register int i;
  473.     int pts, bts, bleft, nl;
  474.     if (!b->length) {
  475.         Iasint(a, 0);
  476.         return;
  477.     }
  478.     if (a==b) {
  479.         Islasint(a, count);
  480.         return;
  481.     }
  482.     pts=count/LOGPLACE;
  483.     bts=count%LOGPLACE;
  484.     bleft=LOGPLACE-bts;
  485.     nl=b->length+pts+1;
  486.     if (nl>a->maxlength) {
  487.         delvec(a->vec, a->maxlength);
  488.         a->maxlength=nl;
  489.         a->vec=newvec(&a->maxlength);
  490.     }
  491.     a->sign=b->sign;
  492.     pa=a->vec;
  493.     pb=b->vec;
  494.     for (i=0; i<pts; i++) 
  495.         pa[i]=0;
  496.     if ( !bts ) {
  497.         for (i=0; i<b->length; i++)
  498.             pa[i+pts]=pb[i];
  499.         a->length=nl-1;
  500.         return;
  501.     }
  502.     accu=0;
  503.     for (i=0; i<b->length; i++) {
  504.         help=pb[i];
  505.         accu|=(help<<bts);
  506.         pa[i+pts]=accu;
  507.         accu=help>>bleft;
  508.     }
  509.     pa[nl-1]=accu;
  510.     if (accu)
  511.         a->length=nl;
  512.     else
  513.         a->length=nl-1;
  514. }        /* IasIslint */
  515.  
  516. void Islasint(a, count)
  517.     register pInteger a;
  518.     unsigned int count;
  519. /* Shift nach links */
  520. {    register PLACE accu, help, *pa, *pb;
  521.     register int i;
  522.     int pts, bts, bleft, nl, maxl;
  523.     if (!a->length)
  524.         return;
  525.     pts=count/LOGPLACE;
  526.     nl=a->length+pts+1;
  527.     if (nl>a->maxlength) {
  528.         pb=a->vec;
  529.         maxl=nl;
  530.         pa=newvec(&maxl);
  531.     } else {
  532.         pa=pb=a->vec;
  533.     }
  534.     bts=count%LOGPLACE;
  535.     bleft=LOGPLACE-bts;
  536.     accu=0;
  537.     if ( bts) {
  538.         for (i=a->length-1; i>=0; i--) {
  539.             help=pb[i];
  540.             accu|=(help>>bleft);
  541.             pa[i+pts+1]=accu;
  542.             accu=help<<bts;
  543.         }
  544.         pa[pts]=accu;
  545.     } else {
  546.         pa[nl-1]=0;
  547.         for (i=a->length-1; i>=0; i--)
  548.             pa[i+pts]=pb[i];
  549.     }
  550.     for (i=pts-1; i>=0; i--)
  551.         pa[i]=0;
  552.     if (nl>a->maxlength) {
  553.         delvec(a->vec, a->maxlength);
  554.         a->vec=pa;
  555.         a->maxlength=maxl;
  556.     }
  557.     if (pa[nl-1])
  558.         a->length=nl;
  559.     else
  560.         a->length=nl-1;
  561. }        /* Islasint */
  562.  
  563. BOOLEAN Isr1(a)
  564.     register pInteger a;
  565. {    register int l;
  566.     register BOOLEAN b;
  567.     l=a->length;
  568.     if (!l)
  569.         return 0;
  570.     b=vecsr1(a->vec, l);
  571.     l--;
  572.     if (!a->vec[l])
  573.         a->length=l;
  574.     return b;
  575. }        /* Isr1 */
  576.  
  577. BOOLEAN Ieven(a)
  578.     register const Integer *a;
  579. {    return (!((*(a->vec))&1));
  580. }    /* Ieven */
  581.